#region Copyright and Licensing Notice
// Copyright (C) 2011 Steven Bosnick
// 
// This program is open source software; you can redistribute it 
// and/or modifiy it under the terms of the Eclipse Public License,
// version 1.0.
// 
// This program is distributed in the hope that it will be useful, 
// but WITHOUT ANY WARRANTY; without even the implied
// warranty of MERCHANTABILITY or FITNESS FOR A 
// PARTICULAR PURPOSE. See the Eclipse Public License for more
// details.
// 
// You should have received a copy of the Eclipse Public License 
// along with this program; if not, you can find a copy at
// "http://www.opensource.org/licenses/eclipse-1.0.php".
#endregion
using System;
using System.Runtime.InteropServices;
using BitwiseOre.SharedMemory.Core;
using BitwiseOre.SharedMemory.Core.Primatives;
using BitwiseOre.SharedMemory.JetBrains;
using Moq;
using NUnit.Framework;

namespace BitwiseOre.Tests.SharedMemory.Primatives
{
    [TestFixture,UsedImplicitly]
    public sealed class SharedArrayFixture : AssertionHelper
    {
        [Test(Description = "Checks that the indexer getter returns value from Read")]
        public void IndexerGet_ReturnsReadValue()
        {
            var accessor = new Mock<IUnmanagedMemoryAccessor>();
            var expected = TimeSpan.FromHours(5);
            accessor.Setup(a => a.Read(It.IsAny<long>(), out expected));
            var array = new SharedArray<TimeSpan>(accessor.Object);

            var result = array[0];

            Expect(result, EqualTo(expected), "Result of indexer getter was not the value from Read.");
        }

#pragma warning disable 168
        [Test(Description = "Checks that the indexer getter Reads from an offset based on index and the type of the array")]
        public void IndexerGet_ReadsFromComputedOffset()
        {
            var accessor = new Mock<IUnmanagedMemoryAccessor>();
            var expected = TimeSpan.FromHours(5);
            accessor.Setup(a => a.Read(It.IsAny<long>(), out expected));
            var array = new SharedArray<TimeSpan>(accessor.Object);
            var size = Marshal.SizeOf(typeof (TimeSpan));
            const int index = 5;

            var result = array[index];

            accessor.Verify(a => a.Read(It.Is<long>(i => i == index*size), out expected));
        }
#pragma warning restore 168

        [Test(Description = "Checks that the indexer setter writes the supplied vaule")]
        public void IndexerSet_WritesSuppliedValue()
        {
            var accessor = new TestAccessor();
            var array = new SharedArray<TimeSpan>(accessor);
            var value = TimeSpan.FromHours(5);

            array[0] = value;

            Expect(accessor.WriteCalled, "Write method not called in the accessor.");
            Expect(accessor.Value, EqualTo(value), "Unexpected value written to accessor.");
        }

        [Test(Description = "Checks the the indexer setter writes to an offset based on the index and type of the array")]
        public void IndexerSet_WritesToComputedOffset()
        {
            var accessor = new TestAccessor();
            var array = new SharedArray<TimeSpan>(accessor);
            var size = Marshal.SizeOf(typeof (TimeSpan));
            const int index = 5;

            array[index] = TimeSpan.FromHours(5);

            Expect(accessor.WriteCalled, "Write method not called in the accessor.");
            Expect(accessor.Position, EqualTo(size*index), "Value written to unexpected position.");
        }

        private sealed class TestAccessor : IUnmanagedMemoryAccessor
        {
            public bool WriteCalled;
            public object Value;
            public long Position;

            public void Read<T>(long position, out T structure) where T : struct
            {
                throw new NotImplementedException();
            }

            public void Write<T>(long position, ref T structure) where T : struct
            {
                WriteCalled = true;
                Position = position;
                Value = structure;
            }

            public long Capacity
            {
                get { throw new NotImplementedException(); }
            }

            public int ReadArray<T>(long position, T[] array, int offset, int count) where T : struct
            {
                throw new NotImplementedException();
            }

            public void WriteArray<T>(long position, T[] array, int offset, int count) where T : struct
            {
                throw new NotImplementedException();
            }
        }
    }
}